package pdm.traj.query.impl;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import pdm.traj.entity.PartInfo;
import pdm.traj.entity.TrackPoint2;
import pdm.traj.entity.TrajQuery;
import pdm.traj.service.KeyService;
import pdm.traj.service.PartService;
import pdm.traj.util.TrajConstants;

public class QueryTask extends Thread {
	private String TAG = "tid:" + String.valueOf(this.getId());
	private Log log = LogFactory.getLog(QueryTask.class);
	private PartService partService;
	private KeyService keyService;
	
	private TrajQuery query;
	private List<TrackPoint2> result;
	private boolean resultReady = false;
	
	private int tCount;//thread count
	private boolean[] readyBitmap;
	private List<QueryMultiTraj> clis;//clients 
	
	
//	public static List<TrackPoint2> queryMultiTraj(TrajQuery query) {
//		QueryTask queryTask = new QueryTask();
//		queryTask.set
//	}
	
	@Override
	public void run() {
		// init 
		if (query == null) {
			log.error(TAG + "run(): query null value");
			return;
		}
		
		//check query input
		Date startTime, endTime;
		try {
			startTime = TrajConstants.TIMESTAMP_FORMAT.parse(query.getStartTime());
			endTime = TrajConstants.TIMESTAMP_FORMAT.parse(query.getEndTime());
		} catch (ParseException pe) {
			log.error(TAG + "run(): startTime or endTime parse fail");
			return;
		}
		// query start		
		result = new ArrayList<TrackPoint2>();
		List<PartInfo> partInfo = partService.getPartInfoByQuery(query);
		tCount =  partInfo.size();
		if (tCount > 0) {
			result = new ArrayList<TrackPoint2>();
			readyBitmap = new boolean[tCount];
			clis = new ArrayList<QueryMultiTraj>();
//			clis.clear();
			for (PartInfo pi : partInfo) {
				List<String> k = keyService.getKeysByPartInfoAndQuery(pi, query);
				QueryMultiTraj cli = new QueryMultiTraj();
				cli.setIp(pi.getIp());
				cli.setPort(pi.getPort());
				cli.setKeys(k);
				cli.setUids(query.getUids());
				cli.setKeyService(keyService);				
				cli.setStartTime(startTime);
				cli.setEndTime(endTime);
				clis.add(cli);				
				cli.start();
//				try {
//					cli.join();
//					result.addAll(cli.getResult());
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				}
			}
			TimerTask checkQueryReady = new CheckQueryReady();
			Timer timer = new Timer();
			timer.scheduleAtFixedRate(checkQueryReady, 10, 10);
			try {
//				this.wait();
//				wait();
				while (!resultReady) {
					Thread.sleep(5);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				timer.cancel();
			}
		}
//		return result;
	}
	
	class CheckQueryReady extends TimerTask {
		@Override
		public void run() {
			boolean allReady = true;
			for (int i = 0; i < tCount; i++) {
				if (!readyBitmap[i]) {
					allReady = false;
					if (!clis.get(i).isAlive()) {
						readyBitmap[i] = true;
						//collect data
						result.addAll(clis.get(i).getResult());
					}
				}
			}
			if (allReady) {
				resultReady = true;
//				QueryTask.this.notify();
			}
		}
	}
	
	public PartService getPartService() {
		return partService;
	}

	public void setPartService(PartService partService) {
		this.partService = partService;
	}

	public KeyService getKeyService() {
		return keyService;
	}

	public void setKeyService(KeyService keyService) {
		this.keyService = keyService;
	}

	public TrajQuery getQuery() {
		return query;
	}

	public void setQuery(TrajQuery query) {
		this.query = query;
	}

	public List<TrackPoint2> getResult() {
		return result;
	}

	public void setResult(List<TrackPoint2> result) {
		this.result = result;
	}

	public boolean isResultReady() {
		return resultReady;
	}

	public void setResultReady(boolean resultReady) {
		this.resultReady = resultReady;
	}

}
